#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAX_ROWS 24
#define MAX_COLS 30

typedef enum {
	LEFT_CLICK = 1,
	RIGHT_CLICK_MINE = 2,
	RIGHT_CLICK_QUESTION = 3,
	RIGHT_CLICK_UNMARK = 4,
	DOUBLE_CLICK = 9
} ActionType;

typedef struct {
	int type;
	int x;
	int y;
} Action;

typedef struct {
	int rows;
	int cols;
	int mines;
	char board[MAX_ROWS][MAX_COLS];
	char display[MAX_ROWS][MAX_COLS];
	int remaining_mines;
	int opened_cells;
	bool game_over;
} Game;

void initialize_game(Game* game, int difficulty, int custom_rows, int custom_cols, int custom_mines);
void print_game(Game* game, int step);
bool perform_action(Game* game, Action action, int step);
int count_adjacent_mines(Game* game, int row, int col);
void open_adjacent_cells(Game* game, int row, int col);
bool check_win(Game* game);

int main() {
	int difficulty;
	scanf("%d", &difficulty);

	int custom_rows = 0, custom_cols = 0, custom_mines = 0;
	if (difficulty == 4) {
		scanf("%d %d %d", &custom_rows, &custom_cols, &custom_mines);
	}

	Game game;
	initialize_game(&game, difficulty, custom_rows, custom_cols, custom_mines);

	for (int i = 0; i < game.rows; ++i) {
		for (int j = 0; j < game.cols; ++j) {
			scanf(" %c", &game.board[i][j]);
			if (game.board[i][j] == '*') {
				game.remaining_mines++;
			}
		}
	}

	Action action;
	int step = 0;
	while (scanf("%d %d %d", &action.type, &action.x, &action.y) != EOF) {
		step++;
		if (!perform_action(&game, action, step)) {
			step--;
		}
	}

	return 0;
}

void initialize_game(Game* game, int difficulty, int custom_rows, int custom_cols, int custom_mines) {
	switch (difficulty) {
	case 1:
		game->rows = 9;
		game->cols = 9;
		game->mines = 10;
		break;
	case 2:
		game->rows = 16;
		game->cols = 16;
		game->mines = 40;
		break;
	case 3:
		game->rows = 16;
		game->cols = 30;
		game->mines = 99;
		break;
	case 4:
		game->rows = custom_rows;
		game->cols = custom_cols;
		game->mines = custom_mines;
		break;
	}

	for (int i = 0; i < game->rows; ++i) {
		for (int j = 0; j < game->cols; ++j) {
			game->display[i][j] = '.';
		}
	}

	game->remaining_mines = 0;
	game->opened_cells = 0;
	game->game_over = false;
}
void print_game(Game* game, int step) {
	if (game->game_over) {
		if (check_win(game)) {
			printf("Game over, you win\n");
		}
		else {
			printf("Hit mine, you lose\n");
		}
	}
	else {
		printf("Game in progress\n");
	}

	printf("%d %d\n", step, game->remaining_mines);

	for (int i = 0; i < game->rows; ++i) {
		for (int j = 0; j < game->cols; ++j) {
			if (game->game_over) {
				if (game->board[i][j] == '*') {
					printf("*");
				}
				else {
					printf("%c", game->display[i][j]);
				}
			}
			else {
				printf("%c", game->display[i][j]);
			}
		}
		printf("\n");
	}
}

bool perform_action(Game* game, Action action, int step) {
	int row = action.x - 1;
	int col = action.y - 1;

	if (row < 0 || row >= game->rows || col < 0 || col >= game->cols) {
		return false;
	}

	if (game->game_over) {
		print_game(game, step);
		return false;
	}

	switch (action.type) {
	case LEFT_CLICK:
		if (game->display[row][col] == '.' && game->board[row][col] != '*') {
			int adjacent_mines = count_adjacent_mines(game, row, col);
			game->display[row][col] = adjacent_mines == 0 ? '_' : '0' + adjacent_mines;
			game->opened_cells++;

			if (adjacent_mines == 0) {
				open_adjacent_cells(game, row, col);
			}

			if (check_win(game)) {
				game->game_over = true;
			}
		}
		else if (game->board[row][col] == '*') {
			game->game_over = true;
		}
		break;

	case RIGHT_CLICK_MINE:
		if (game->display[row][col] == '.') {
			game->display[row][col] = 'F';
			game->remaining_mines--;
		}
		break;

	case RIGHT_CLICK_QUESTION:
		if (game->display[row][col] == 'F') {
			game->display[row][col] = '?';
			game->remaining_mines++;
		}
		break;

	case RIGHT_CLICK_UNMARK:
		if (game->display[row][col] == '?') {
			game->display[row][col] = '.';
		}
		break;

	case DOUBLE_CLICK:
		if (game->display[row][col] >= '1' && game->display[row][col] <= '8') {
			int flag_count = 0;
			for (int i = -1; i <= 1; ++i) {
				for (int j = -1; j <= 1; ++j) {
					if (row + i >= 0 && row + i < game->rows && col + j >= 0 && col + j < game->cols) {
						if (game->display[row + i][col + j] == 'F') {
							flag_count++;
						}
					}
				}
			}

			if (flag_count == game->display[row][col] - '0') {
				for (int i = -1; i <= 1; ++i) {
					for (int j = -1; j <= 1; ++j) {
						if (row + i >= 0 && row + i < game->rows && col + j >= 0 && col + j < game->cols) {
							Action new_action = { LEFT_CLICK, row + i + 1, col + j + 1 };
							perform_action(game, new_action, step);
						}
					}
				}
			}
		}
		break;

	default:
		return false;
	}

	print_game(game, step);
	return true;
}

int count_adjacent_mines(Game* game, int row, int col) {
	int count = 0;

	for (int i = -1; i <= 1; ++i) {
		for (int j = -1; j <= 1; ++j) {
			if (row + i >= 0 && row + i < game->rows && col + j >= 0 && col + j < game->cols) {
				if (game->board[row + i][col + j] == '*') {
					count++;
				}
			}
		}
	}

	return count;
}

void open_adjacent_cells(Game* game, int row, int col) {
	for (int i = -1; i <= 1; ++i) {
		for (int j = -1; j <= 1; ++j) {
			if (row + i >= 0 && row + i < game->rows && col + j >= 0 && col + j < game->cols) {
				if (game->display[row + i][col + j] == '.') {
					int adjacent_mines = count_adjacent_mines(game, row + i, col + j);
					game->display[row + i][col + j] = adjacent_mines == 0 ? '_' : '0' + adjacent_mines;
					game->opened_cells++;

					if (adjacent_mines == 0) {
						open_adjacent_cells(game, row + i, col + j);
					}
				}
			}
		}
	}
}

bool check_win(Game* game) {
	return game->opened_cells == game->rows * game->cols - game->mines;
}